package com.mgq.netty.chat.protocol;




import com.mgq.netty.chat.config.ConfigProperties;
import com.mgq.netty.chat.message.Message;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageCodec;
import lombok.extern.slf4j.Slf4j;

import java.util.List;

/**
 * @author MaGuangQi
 * netty 使用了@Shareable注解,来标记一个这个Handler是可以被其他channel共享的.
 * 我们的MessageCodec是可以被共享的,因为经过LengthFieldBasedFrameDecoder处理后,我们的message都是完整的
 * 当时当我们标记MessageCodec类的@Shareable,会抛出错误,netty不允许.解决办法
 * 使用MessageToMessageCodec.因为ByteToMessageCodec,netty认为ByteToMessageCodec将ByteBuf转化为Message，
 * 意味着传进该handler的数据还未被处理过。所以传过来的ByteBuf可能并不是完整的数据，如果共享则会出现问题.
 * @date 2021-12-07 11:19
 **/
@Slf4j
@ChannelHandler.Sharable
public class MessageCodecShare extends MessageToMessageCodec<ByteBuf, Message> {
    @Override
    protected void encode(ChannelHandlerContext ctx, Message msg, List<Object> outList) throws Exception {
        ByteBuf out = ctx.alloc().buffer();
        // 4个字节的魔数
        out.writeBytes(new byte[]{1,2,3,4});
        //1个字节的版本号
        out.writeByte(1);
        //1个字节的序列化算法: 0 jdk,1.gson
        //枚举的ordinal()方法,返回枚举对象的序号,从0开始,此时Java为0,Gson为1
        out.writeByte(ConfigProperties.getSerializerAlgorithm().ordinal());
        //1个字节的消息类型
        out.writeByte(msg.getMessageType());
        //4个字节的请求序号
        out.writeInt(msg.getSequenceId());
        //5.填充1个字节,凑够16个字节
        out.writeByte(0xff);
        //正文长度
        byte[] bytes = Serializer.Algorithm.values()[ConfigProperties.getSerializerAlgorithm().ordinal()].serialize(msg);
        //长度用4个字节
        out.writeInt(bytes.length);
        //写入消息正文
        out.writeBytes(bytes);

        outList.add(out);
    }

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        //直接从ByteBuf读取即可
        //1. 4个字节的魔数
        int magicNum = in.readInt();
        //2.version
        byte version = in.readByte();

        //3.序列化算法
        byte serializeType = in.readByte();
        //4.消息类型
        byte messageType = in.readByte();
        //5.序号id
        int sequenceId = in.readInt();
        //6.补齐的字节
        in.readByte();
        //7.长度
        int length = in.readInt();
        //8.正文
        byte[] bytes = new byte[length];
        //将正文写入到bytes中
        in.readBytes(bytes, 0, length);
        //枚举的values()方法,返回枚举的序号值集合(0,1),和枚举对应
        Serializer.Algorithm algorithm = Serializer.Algorithm.values()[serializeType];
        //处理反序列化的类型(Message是个抽象类),Gson反序列化,需要指定具体的类型
        //解决办法 Message抽象类定义了一个集合,保存了消息类型和class对应的关系
        Class<?> messageClass = Message.getMessageClass(messageType);
        Object message = algorithm.deSerialize(messageClass, bytes);
        //记得将消息传递给下一个Handler处理.
        out.add(message);
        //log.debug("{},{},{},{},{}",magicNum,version,serializeType,sequenceId,length);
       // log.debug("message:{}",message);
    }
}
